package drds.plus.sql_process.optimizer.cost_esitimater;

import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.JoinStrategy;
import drds.plus.sql_process.abstract_syntax_tree.expression.bind_value.BindValue;
import drds.plus.sql_process.abstract_syntax_tree.node.query.Join;
import drds.plus.sql_process.abstract_syntax_tree.node.query.Query;

public class JoinNodeCostEstimater implements CostEstimater {

    public Cost estimate(Query query) {
        Join joinNode = (Join) query;

        Cost leftCost = CostEsitimaterFactory.estimate(joinNode.getLeftNode());
        Cost rightCost = CostEsitimaterFactory.estimate(joinNode.getRightNode());
        Cost cost = new Cost();
        cost.setDependentOnOtherQuery(true);
        long keyFilteredCount = 0;
        long keyFilteredAndValueFilteredCount = 0;
        boolean dependentOnOtherQuery = true;// join
        long networkTransferCount = 0;
        //
        // 估算IO开销(最差的情况)
        if (rightCost.isDependentOnOtherQuery()) {
            cost.setDiskIoCost(leftCost.getDiskIoCost() + rightCost.getDiskIoCost());// 最差情况
        } else {
            cost.setDiskIoCost(leftCost.getDiskIoCost() + //
                    leftCost.getKeyFilteredAndValueFilteredCount());// 只管结果
        }
        // 估算网络开销
        if (joinNode.getDataNodeId() != null) {
            if (!joinNode.getDataNodeId().equals(joinNode.getLeftNode().getDataNodeId())) {
                networkTransferCount += leftCost.getKeyFilteredAndValueFilteredCount();
            }
            if (!joinNode.getDataNodeId().equals(joinNode.getRightNode().getDataNodeId())) {
                networkTransferCount += rightCost.getKeyFilteredAndValueFilteredCount();
            }
        }
        // 如果是IndexNestLoop，则数据还在磁盘上
        if (joinNode.getJoinStrategy() == JoinStrategy.index_nest_loop_join) {
            cost.setDiskIoCost(leftCost.getKeyFilteredAndValueFilteredCount());
            dependentOnOtherQuery = false;
            keyFilteredCount = leftCost.getKeyFilteredCount() + // 左边
                    rightCost.getKeyFilteredCount();// 右边读
        } else {
            // sort sort
            // 右边的先要拿出数据
            // 再要将符合的数据插到临时表(要走临时表)
            // 所以等于是两次
            keyFilteredCount = leftCost.getKeyFilteredCount() + // 左边
                    rightCost.getKeyFilteredCount() + // 右边读
                    rightCost.getKeyFilteredCount() + // 右边写
                    rightCost.getKeyFilteredAndValueFilteredCount();// 再查询出来
        }
        // 估算行数
        // 现在假定join后的行数为较小表的行数(min)，这个假设对于大多数场景都是成立的
        if (leftCost.getKeyFilteredAndValueFilteredCount() < rightCost.getKeyFilteredAndValueFilteredCount()) {
            keyFilteredAndValueFilteredCount = (leftCost.getKeyFilteredAndValueFilteredCount());
        } else {
            keyFilteredAndValueFilteredCount = (rightCost.getKeyFilteredAndValueFilteredCount());
        }
        //
        if (query.getLimitFrom() != null && query.getLimitTo() != null) {
            Object from = query.getLimitFrom();
            if (from instanceof BindValue) {
                from = ((BindValue) from).getValue();
            }
            Object to = query.getLimitTo();
            if (to instanceof BindValue) {
                to = ((BindValue) to).getValue();
            }
            if (from instanceof Long && to instanceof Long) {
                keyFilteredAndValueFilteredCount = (Long) from - (Long) to;
            }
        } else if (query.getLimitFrom() != null || query.getLimitTo() != null) {
            // tddl代码:keyFilteredAndValueFilteredCount = keyFilteredAndValueFilteredCount /
            // 2;
            // keyFilteredAndValueFilteredCount-from or keyFilteredAndValueFilteredCount-to
            // by czh
            if (query.getLimitFrom() != null) {
                Object from = query.getLimitFrom();
                if (from instanceof BindValue) {
                    from = ((BindValue) from).getValue();
                }
                if (from instanceof Long) {
                    keyFilteredAndValueFilteredCount = keyFilteredAndValueFilteredCount - (Long) from;
                }
            }
            if (query.getLimitTo() != null) {
                Object to = query.getLimitTo();
                if (to instanceof BindValue) {
                    to = ((BindValue) to).getValue();
                }
                if (to instanceof Long) {
                    keyFilteredAndValueFilteredCount = keyFilteredAndValueFilteredCount - (Long) to;
                }
            }
        }
        cost.setKeyFilteredCount(keyFilteredCount);
        cost.setKeyFilteredAndValueFilteredCount(keyFilteredAndValueFilteredCount);
        cost.setDependentOnOtherQuery(dependentOnOtherQuery);
        cost.setNetworkTransferCount(networkTransferCount);
        return cost;
    }
}
